﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : MultiServerEngine | ServerFramework | ClientPeer.cs
// //  Created : 2016 - 02 - 16 20:53
// //  Modified: 2016 - 02 - 20 12:32
// //  ********************************************************************************

using System;
using ExitGames.Logging;
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
using ServerFramework.Implementation.Telegram;
using ServerFramework.Interfaces.Application;
using ServerFramework.Interfaces.Client;
using ServerFramework.Interfaces.Handler;
using TypeDefs;

namespace ServerFramework.Implementation.Client
{
    public class ClientPeer : PeerBase, IClientPeer
    {
        private IServerApplication Server { get; }
        private IClientPeerRegistry<IClientPeer> ClientPeerRegistry { get; }
        private ITelegramHandlerRegistry TelegramHandlerRegistry { get; }

        public ILogger Logger { get; }
        public Guid PeerId { get; }

        public ClientPeer(InitRequest initRequest, ILogger logger, IServerApplication server,
                          IClientPeerRegistry<IClientPeer> clientPeerRegistry,
                          ITelegramHandlerRegistry telegramHandlerRegistry) : base(initRequest)
        {
            Logger = logger;
            Server = server;
            ClientPeerRegistry = clientPeerRegistry;
            TelegramHandlerRegistry = telegramHandlerRegistry;
            PeerId = Guid.NewGuid();
            Logger.InfoFormat("Created new client peer with id={0} on server={1}", PeerId, Server.ServerType);
            Connect();
        }

        public ClientPeer(IRpcProtocol protocol, IPhotonPeer unmanagedPeer, ILogger logger, IServerApplication server,
                          IClientPeerRegistry<IClientPeer> clientPeerRegistry,
                          ITelegramHandlerRegistry telegramHandlerRegistry) : base(protocol, unmanagedPeer)
        {
            Logger = logger;
            Server = server;
            ClientPeerRegistry = clientPeerRegistry;
            TelegramHandlerRegistry = telegramHandlerRegistry;
            PeerId = Guid.NewGuid();
            Logger.InfoFormat("Created new client peer with id={0} on server={1}", PeerId, Server.ServerType);
            Connect();
        }

        public void Connect()
        {
            ClientPeerRegistry.RegisterPeer(this);
        }

        protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
        {
            const TelegramTypes telegramType = TelegramTypes.Request;
            byte code = operationRequest.OperationCode;
            int? subCode = operationRequest.Parameters.ContainsKey((byte) ParameterCodes.SubCode)
                ? Convert.ToInt32(operationRequest.Parameters[(byte) ParameterCodes.SubCode])
                : (int?) null;

            Logger.InfoFormat("Received OperationRequest with code={0}, sub-code={1} on client={2}", code, subCode,
                PeerId);

            // Do we have client handlers registered on this server the client is created on?
            if (Server.GetHandledOperations().ContainsKey(HandlerTypes.ClientHandler))
            {
                // Does the list of client handlers contain a handler with an operation code matching the operation code of the request?
                if (Server.GetHandledOperations()[HandlerTypes.ClientHandler].Contains((OperationCodes) code))
                {
                    // Get the handler that is most specific capable handling the request
                    ITelegramHandler<IClientPeer> handler = TelegramHandlerRegistry.GetClientHandler(telegramType, code,
                        subCode);

                    // Do we have a valid handler retrieved and can the handler handle the telegram?
                    handler?.HandleTelegram(new RequestTelegram(code, subCode, operationRequest.Parameters), this);
                }
                else
                {
                    Logger.InfoFormat(
                        "Operation with code={0} and sub-code={1} is not handled by server={2}. Trying to forward...",
                        (OperationCodes) code, subCode, Server.ServerType);

                    // Do we have a telegram handler in our registry for forwarding?
                    ITelegramHandler<IClientPeer> handler = TelegramHandlerRegistry.GetClientHandler(telegramType,
                        (byte) OperationCodes.ForwardRequest, null);

                    // Do we have a valid handler?
                    if (handler != null)
                    {
                        handler.HandleTelegram(new RequestTelegram(code, subCode, operationRequest.Parameters), this);
                    }
                    else
                    {
                        Logger.ErrorFormat("No responsible server found. Sending back error response.");

                        // Inform the client that no server was found to handle the request
                        SendOperationResponse(
                            new OperationResponse(operationRequest.OperationCode)
                            {
                                ReturnCode = (short) ErrorCodes.NoServerFound,
                                DebugMessage = "No valid server found to handle telegram."
                            },
                            new SendParameters());
                    }
                }
            }
        }

        protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
        {
            Logger.InfoFormat("Disconnect received with code={0}, reason={1}", reasonCode, reasonDetail);
            ClientPeerRegistry.UnregisterClientPeer(this);
        }
    }
}
